package com.turnengine.client.common.command.executor.data;

import static com.javabi.common.dependency.DependencyFactory.getDependency;

import java.io.IOException;

import com.javabi.command.IExecutableCommandResponse;
import com.javabi.command.errorcode.IErrorCodeSet;
import com.javabi.command.errorcode.data.IErrorCodeSetSerializer;
import com.javabi.command.serializer.ICommandDataSerializer;
import com.javabi.common.io.data.IDataReader;
import com.javabi.common.io.data.IDataWriter;

public abstract class AbstractCommandDataSerializer<R> implements ICommandDataSerializer<R> {

	private static final byte ERRORS = 1;
	private static final byte RETURN_VALUE = 0;

	private final short commandId;
	private IErrorCodeSetSerializer serializer = getDependency(IErrorCodeSetSerializer.class);

	protected AbstractCommandDataSerializer(short commandId) {
		this.commandId = commandId;
	}

	@Override
	public short getCommandId() {
		return commandId;
	}

	@Override
	public IExecutableCommandResponse<R> readResponse(IDataReader reader) throws IOException {
		byte type = reader.readByte();
		if (type == ERRORS) {
			IErrorCodeSet errors = serializer.readObject(reader);
			IExecutableCommandResponse<R> response = newResponse();
			response.setCommandId(getCommandId());
			response.setErrors(errors);
			return response;
		}
		if (type == RETURN_VALUE) {
			R returnValue = readReturnValue(reader);
			IExecutableCommandResponse<R> response = newResponse();
			response.setCommandId(getCommandId());
			response.setReturnValue(returnValue);
			return response;
		}
		throw new IllegalStateException("unexpected byte read: " + type);
	}

	@Override
	public void writeResponse(IDataWriter writer, IExecutableCommandResponse<R> response) throws IOException {
		if (response.hasErrors()) {
			writer.writeByte(ERRORS);
			serializer.writeObject(writer, response.getErrors());
		} else {
			writer.writeByte(RETURN_VALUE);
			writeReturnValue(writer, response.getReturnValue());
		}
	}

	public abstract IExecutableCommandResponse<R> newResponse();

}
